package org.example.plugin;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.example.service.WorkerService;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;

@Component
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Slf4j
public class DataChangePlugin implements Interceptor {
    private Map<String,DataChangeInterface> dataChangeInterfaceMap = Maps.newConcurrentMap();

    @PostConstruct
    public void init(){
        Map<String, DataChangeInterface> beansOfType = SpringUtil.getBeansOfType(DataChangeInterface.class);
        if(CollectionUtil.isNotEmpty(beansOfType)){
            Collection<DataChangeInterface> values = beansOfType.values();
            values.forEach( dataChangeInterface -> dataChangeInterfaceMap.put(dataChangeInterface.namespaceName(),dataChangeInterface));
        }
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        handle(invocation);

        return invocation.proceed();
    }


    /***
     * 处理数据变化
     * @param invocation
     */
    private void handle(Invocation invocation){
        MappedStatement ms = (MappedStatement) invocation.getArgs()[0];

        Object parameter = invocation.getArgs()[1];


        String id = ms.getId();

        String namespace = id.substring(0, id.lastIndexOf("."));

        if(!dataChangeInterfaceMap.containsKey(namespace)){
            return;
        }
        DataChangeInterface dataChangeInterface = dataChangeInterfaceMap.get(namespace);

        // 处理不同的 SQL 命令类型
        switch (ms.getSqlCommandType()) {
            case INSERT:
                dataChangeInterface.insert(parameter);
                break;
            case UPDATE:
                String prefix = namespace + "." + "delete";
                handleUpdateOrDelete(parameter,prefix,id,dataChangeInterface);
                break;
            case DELETE:
//                handleDelete(parameter);
                break;
        }
    }


    /***
     * 判断逻辑删除
     * @param parameter
     * @param delPrefix
     * @param id
     * @param dataChangeInterface
     */
    private void handleUpdateOrDelete(Object parameter,String delPrefix,String id,DataChangeInterface dataChangeInterface){
        if(id.startsWith(delPrefix)){
            dataChangeInterface.delete(parameter);
        }else {
            dataChangeInterface.update(parameter);
        }
    }

    // 处理更新操作



    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {
        // 可用于读取配置文件中的参数
    }


    /***
     * 解析sql 是否含有某个表
     * @param sql
     * @param tableName
     * @return
     */
    private boolean isUpdateTargetTable(String sql,String tableName) {
        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            if (statement instanceof Update) {
                Update update = (Update) statement;
                return update.getTable().getName().equalsIgnoreCase(tableName);
            }
        } catch (JSQLParserException e) {
            e.printStackTrace();
        }
        return false;
    }

    /***
     * 解析 update 操作要更新的字段
     * @param sql
     * @return
     */
    private String[] getUpdatedFields(String sql) {
        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            if (statement instanceof Update) {
                Update update = (Update) statement;
                List<String> fields = new ArrayList<>();
                update.getUpdateSets().forEach(updateSet -> fields.add(updateSet.getColumns().get(0).getColumnName()));
                return fields.toArray(new String[0]);
            }
        } catch (JSQLParserException e) {
            e.printStackTrace();
        }
        return new String[0];
    }


}    